/*
 * File      : dfs_lfs.c
 * This file is part of Suzhou Allen
 * COPYRIGHT (C) 2006 - 2017, Allen Development Team
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018��2��11��     Urey      first version
 */
#include <rtthread.h>
#include <rtdevice.h>

#include <dfs_fs.h>
#include <dfs_file.h>

#include "lfs.h"

#include <stdio.h>
#include <string.h>


#define RT_DFS_LFS_DRIVES    4
#ifndef LFS_READ_SIZE
#  define LFS_READ_SIZE   64
#endif

#ifndef LFS_PROG_SIZE
#  define LFS_PROG_SIZE   64
#endif

#ifndef LFS_BLOCK_SIZE
#  define LFS_BLOCK_SIZE  512
#endif

#ifndef LFS_LOOKAHEAD
#  define LFS_LOOKAHEAD   512
#endif


typedef struct _dfs_lfs_s
{
    struct lfs          lfs;
    struct lfs_config   cfg;
}dfs_lfs_t;

//typedef struct _dfs_lfs_file_s
//{
//    struct lfs*         lfs;
//    struct lfs_file     file;
//}dfs_lfs_file_t;
//
//typedef struct _dfs_lfs_dir_s
//{
//    struct lfs*         lfs;
//    struct lfs_dir      dir;
//}dfs_lfs_dir_t;

typedef struct _dfs_lfs_fd_s
{
    struct lfs*         lfs;
    union
    {
        struct lfs_file file;
        struct lfs_dir  dir;
    }u;
}dfs_lfs_fd_t;

static struct _dfs_lfs_s* _lfs_mount_tbl[RT_DFS_LFS_DRIVES] = {0};




// Read a region in a block. Negative error codes are propogated
// to the user.
int _lfs_flash_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
{
    struct rt_mtd_nor_device* mtd_nor;

    RT_ASSERT(c != RT_NULL);
    RT_ASSERT(c->context != RT_NULL);

    mtd_nor = (struct rt_mtd_nor_device*)c->context;
    rt_mtd_nor_read(mtd_nor,block * c->block_size + off,buffer,size);

    return LFS_ERR_OK;
}

// Program a region in a block. The block must have previously
// been erased. Negative error codes are propogated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
int _lfs_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
{
    struct rt_mtd_nor_device* mtd_nor;

    RT_ASSERT(c != RT_NULL);
    RT_ASSERT(c->context != RT_NULL);

    mtd_nor = (struct rt_mtd_nor_device*)c->context;
    rt_mtd_nor_write(mtd_nor,block*c->block_size + off,buffer,size);

    return LFS_ERR_OK;
}

// Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes
// are propogated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
int _lfs_flash_erase(const struct lfs_config *c, lfs_block_t block)
{
    struct rt_mtd_nor_device* mtd_nor;

    RT_ASSERT(c != RT_NULL);
    RT_ASSERT(c->context != RT_NULL);

    mtd_nor = (struct rt_mtd_nor_device*)c->context;
    rt_mtd_nor_erase_block(mtd_nor,block * c->block_size,c->block_size);

    return LFS_ERR_OK;
}

// Sync the state of the underlying block device. Negative error codes
// are propogated to the user.
int _lfs_flash_sync(const struct lfs_config *c)
{
    return LFS_ERR_OK;
}



/* results:
 *  -1, no space to install fatfs driver
 *  >= 0, there is an space to install fatfs driver
 */
static int get_disk(rt_device_t dev_id)
{
    int index;

    if(dev_id == RT_NULL)
    {
        for (index = 0; index < RT_DFS_LFS_DRIVES; index ++)
        {
            if(_lfs_mount_tbl[index] == RT_NULL)
                return index;
        }
    }
    else
    {
        for (index = 0; index < RT_DFS_LFS_DRIVES; index ++)
        {
            if((_lfs_mount_tbl[index] != RT_NULL) &&(_lfs_mount_tbl[index]->cfg.context == (void *)dev_id))
                return index;
        }
    }

    return -1;
}


static int lfs_result_to_dfs(int result)
{
    int status = 0;

    switch (result)
    {
    case LFS_ERR_OK:
        break;
    case LFS_ERR_IO       : status = -EIO;      break;      // Error during device operation
    case LFS_ERR_NOENT    : status = -ENOENT;   break;      // No directory entry
    case LFS_ERR_EXIST    : status = -EEXIST;   break;      // Entry already exists
    case LFS_ERR_NOTDIR   : status = -ENOTDIR;  break;      // Entry is not a dir
    case LFS_ERR_ISDIR    : status = -EISDIR;   break;      // Entry is a dir
    case LFS_ERR_NOTEMPTY : status = -ENOTEMPTY;break;      // Dir is not empty
    case LFS_ERR_BADF     : status = -EBADF;    break;      // Bad file number
    case LFS_ERR_INVAL    : status = -EINVAL;   break;      // Invalid parameter
    case LFS_ERR_NOSPC    : status = -ENOSPC;   break;      // No space left on device
    case LFS_ERR_NOMEM    : status = -ENOMEM;   break;      // No more memory available
    case LFS_ERR_CORRUPT  : status = -52;       break;      // Corrupted
    default               : status = -EIO;      break;
    }

    return status;
}

static int dfs_lfs_mount(struct dfs_filesystem *dfs, unsigned long rwflag, const void *data)
{
    int result;
    dfs_lfs_t *dfs_lfs;
    int index;

    /* Check Device Type */
    if(dfs->dev_id->type != RT_Device_Class_MTD)
    {
        rt_kprintf("The flash device type must be MTD!\n");
        return -EINVAL;
    }

    /* get an empty position */
    index = get_disk(RT_NULL);
    if (index == -1)
        return -EIO;

    /*create lfs handle */
    dfs_lfs = rt_malloc(sizeof(dfs_lfs_t));
    if(dfs_lfs == RT_NULL)
    {
        rt_kprintf("ERROR:no memory!\n");

        _lfs_mount_tbl[index] = RT_NULL;
        return -ENOMEM;
    }
    rt_memset(dfs_lfs,0,sizeof(dfs_lfs_t));

    { /* init cfg data */
        struct rt_mtd_nor_device *mtd_nor = (struct rt_mtd_nor_device *)dfs->dev_id;

        dfs_lfs->cfg.context     = (void *)mtd_nor;

        dfs_lfs->cfg.read_size = mtd_nor->block_size;
        if(dfs_lfs->cfg.read_size < LFS_READ_SIZE)
            dfs_lfs->cfg.read_size = LFS_READ_SIZE;

        dfs_lfs->cfg.prog_size = mtd_nor->block_size;
        if(dfs_lfs->cfg.prog_size < LFS_PROG_SIZE)
            dfs_lfs->cfg.prog_size = LFS_PROG_SIZE;

        dfs_lfs->cfg.block_size = mtd_nor->block_size;
        if (dfs_lfs->cfg.block_size < LFS_BLOCK_SIZE)
            dfs_lfs->cfg.block_size = LFS_BLOCK_SIZE;

        dfs_lfs->cfg.block_count = mtd_nor->block_end - mtd_nor->block_start;

        dfs_lfs->cfg.lookahead = 32 * ((dfs_lfs->cfg.block_count + 31) / 32);
        if (dfs_lfs->cfg.lookahead > LFS_LOOKAHEAD)
        {
            dfs_lfs->cfg.lookahead = LFS_LOOKAHEAD;
        }

        dfs_lfs->cfg.read        = &_lfs_flash_read;
        dfs_lfs->cfg.prog        = &_lfs_flash_prog;
        dfs_lfs->cfg.erase       = &_lfs_flash_erase;
        dfs_lfs->cfg.sync        = &_lfs_flash_sync;
    }

    /* mount lfs*/
    result = lfs_mount(&dfs_lfs->lfs,&dfs_lfs->cfg);
    if(result == LFS_ERR_OK)
    {
        /* save device */
        _lfs_mount_tbl[index] = dfs_lfs;

        /* mount succeed! */
        dfs->data = (void *)dfs_lfs;

        return RT_EOK;
    }

    /* release memory */
    rt_free(dfs_lfs);
    _lfs_mount_tbl[index] = RT_NULL;
    return -EIO;
}


static int dfs_lfs_unmount(struct dfs_filesystem *dfs)
{
    int     index;
    dfs_lfs_t *dfs_lfs = RT_NULL;

    RT_ASSERT(dfs != RT_NULL);
    RT_ASSERT(dfs->data != RT_NULL);

    dfs_lfs = (dfs_lfs_t *)dfs->data;


    /* find the device index and then umount it */
    index = get_disk(dfs->dev_id);
    if (index == -1) /* not found */
        return -ENOENT;

    dfs_lfs = _lfs_mount_tbl[index];
    _lfs_mount_tbl[index] = RT_NULL;
    dfs->data = RT_NULL;

    lfs_unmount(&dfs_lfs->lfs);
    rt_free(dfs_lfs);

    return RT_EOK;
}


static int dfs_lfs_mkfs(rt_device_t dev_id)
{
    dfs_lfs_t *dfs_lfs = RT_NULL;
    int result;
    int index;

    if (dev_id == RT_NULL)
        return -EINVAL;

    /* Check Device Type */
    if(dev_id->type != RT_Device_Class_MTD)
    {
        rt_kprintf("The flash device type must be MTD!\n");
        return -EINVAL;
    }

    index = get_disk(dev_id);
    if (index == -1)
    {
        /* not found the device id */
        index = get_disk(RT_NULL);
        if (index == -1)
        {
            /* no space to store an temp driver */
            rt_kprintf("sorry, there is no space to do mkfs! \n");
            return -ENOSPC;
        }
        else
        {
            /*create lfs handle */
            dfs_lfs = rt_malloc(sizeof(dfs_lfs_t));
            if(dfs_lfs == RT_NULL)
            {
                rt_kprintf("ERROR:no memory!\n");

                _lfs_mount_tbl[index] = RT_NULL;
                return -ENOMEM;
            }
            rt_memset(dfs_lfs,0,sizeof(dfs_lfs_t));

            { /* init cfg data */
                struct rt_mtd_nor_device *mtd_nor = (struct rt_mtd_nor_device *)dev_id;

                dfs_lfs->cfg.context     = (void *)mtd_nor;

                dfs_lfs->cfg.read_size = mtd_nor->block_size;
                if(dfs_lfs->cfg.read_size < LFS_READ_SIZE)
                    dfs_lfs->cfg.read_size = LFS_READ_SIZE;

                dfs_lfs->cfg.prog_size = mtd_nor->block_size;
                if(dfs_lfs->cfg.prog_size < LFS_PROG_SIZE)
                    dfs_lfs->cfg.prog_size = LFS_PROG_SIZE;

                dfs_lfs->cfg.block_size = mtd_nor->block_size;
                if (dfs_lfs->cfg.block_size < LFS_BLOCK_SIZE)
                    dfs_lfs->cfg.block_size = LFS_BLOCK_SIZE;

                dfs_lfs->cfg.block_count = mtd_nor->block_end - mtd_nor->block_start;

                dfs_lfs->cfg.lookahead = 32 * ((dfs_lfs->cfg.block_count + 31) / 32);
                if (dfs_lfs->cfg.lookahead > LFS_LOOKAHEAD)
                {
                    dfs_lfs->cfg.lookahead = LFS_LOOKAHEAD;
                }

                dfs_lfs->cfg.read        = &_lfs_flash_read;
                dfs_lfs->cfg.prog        = &_lfs_flash_prog;
                dfs_lfs->cfg.erase       = &_lfs_flash_erase;
                dfs_lfs->cfg.sync        = &_lfs_flash_sync;
            }
        }
    }
    else
    {
        dfs_lfs =  _lfs_mount_tbl[index];
        _lfs_mount_tbl[index] = RT_NULL;

        /* unmount it */
        lfs_unmount(&dfs_lfs->lfs);
    }

    /* format flash device */
    result = lfs_format(&dfs_lfs->lfs,&dfs_lfs->cfg);
    if(result != LFS_ERR_OK)
    {
        return lfs_result_to_dfs(result);
    }

    /* release rt_spiffs */
    return RT_EOK;
}

static int _dfs_lfs_statfs_count(void *p, lfs_block_t b)
{
    *(lfs_size_t *) p += 1;
    return 0;
}
static int dfs_lfs_statfs(struct dfs_filesystem *dfs, struct statfs *buf)
{
    dfs_lfs_t *dfs_lfs ;
    int          result;
    lfs_size_t  in_use = 0;

    RT_ASSERT(buf != RT_NULL);
    RT_ASSERT(dfs != RT_NULL);
    RT_ASSERT(dfs->data != RT_NULL);

    dfs_lfs = (dfs_lfs_t *)dfs->data;


    /* Get total sectors and free sectors */
    result = lfs_traverse(&dfs_lfs->lfs, _dfs_lfs_statfs_count, &in_use);
    if(result != LFS_ERR_OK)
    {
        return lfs_result_to_dfs(result);
    }
    buf->f_bsize = dfs_lfs->cfg.block_size;

    buf->f_blocks = dfs_lfs->cfg.block_count;
    buf->f_bfree  = dfs_lfs->cfg.block_count - in_use;

    return RT_EOK;
}

static int dfs_lfs_unlink(struct dfs_filesystem *dfs, const char *path)
{
    dfs_lfs_t   *dfs_lfs ;
    int         result;

    RT_ASSERT(dfs != RT_NULL);
    RT_ASSERT(dfs->data != RT_NULL);
    dfs_lfs = (dfs_lfs_t *)dfs->data;

    result = lfs_remove(&dfs_lfs->lfs,path);
    return lfs_result_to_dfs(result);
}

static void _dfs_lfs_tostat(struct stat *st, struct lfs_info *info)
{
    memset(st, 0, sizeof(struct stat));

    /* convert to dfs stat structure */
    st->st_dev = 0;
    st->st_size = info->size;
    st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;

    switch (info->type)
    {
        case LFS_TYPE_DIR:
            st->st_mode |= S_IFDIR;
        break;
        case LFS_TYPE_REG:
            st->st_mode |= S_IFREG;
        break;
    }

}

int dfs_lfs_stat(struct dfs_filesystem *dfs, const char *path, struct stat *st)
{
    dfs_lfs_t   *dfs_lfs;
    int         result;
    struct lfs_info info;

    RT_ASSERT(dfs != RT_NULL);
    RT_ASSERT(dfs->data != RT_NULL);
    dfs_lfs = (dfs_lfs_t *)dfs->data;

    result = lfs_stat(&dfs_lfs->lfs, path, &info);
    if(result != LFS_ERR_OK)
    {
        return lfs_result_to_dfs(result);
    }

    _dfs_lfs_tostat(st, &info);
    return 0;
}

static int dfs_lfs_rename(struct dfs_filesystem *dfs, const char *from, const char *to)
{
    dfs_lfs_t   *dfs_lfs;
    int         result;

    RT_ASSERT(dfs != RT_NULL);
    RT_ASSERT(dfs->data != RT_NULL);
    dfs_lfs = (dfs_lfs_t *)dfs->data;

    result = lfs_rename(&dfs_lfs->lfs, from, to);
    return lfs_result_to_dfs(result);
}


/******************************************************************************
 * file operations
 ******************************************************************************/
static int dfs_lfs_open(struct dfs_fd *file)
{
    struct dfs_filesystem* dfs;
    dfs_lfs_t* dfs_lfs;
    int result;
    int flags = 0;

    RT_ASSERT(file != RT_NULL);
    RT_ASSERT(file->data != RT_NULL);
    dfs = (struct dfs_filesystem *) file->data;
    dfs_lfs = (dfs_lfs_t *)dfs->data;

    if (file->flags & O_DIRECTORY)
    {
        dfs_lfs_fd_t*   dfs_lfs_fd  = rt_malloc(sizeof(dfs_lfs_fd_t));
        if(dfs_lfs_fd == RT_NULL)
        {
            rt_kprintf("ERROR:no memory!\n");
            result = -ENOMEM;

            goto _error_dir;
        }
        rt_memset(dfs_lfs_fd,0,sizeof(dfs_lfs_fd_t));
        dfs_lfs_fd->lfs = &dfs_lfs->lfs;


        if (file->flags & O_CREAT)
        {
            result = lfs_mkdir(dfs_lfs_fd->lfs,file->path);
            if (result != LFS_ERR_OK)
            {
                goto _error_dir;
            }
        }

        result = lfs_dir_open(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, file->path);
        if (result != LFS_ERR_OK)
        {
            goto _error_dir;
        }

        file->data = (void *)dfs_lfs_fd;
        return RT_EOK;
_error_dir:
        if(dfs_lfs_fd != RT_NULL)
            rt_free(dfs_lfs_fd);

        return lfs_result_to_dfs(result);
    }
    else
    {
        dfs_lfs_fd_t*   dfs_lfs_fd  = rt_malloc(sizeof(dfs_lfs_fd_t));
        if(dfs_lfs_fd == RT_NULL)
        {
            rt_kprintf("ERROR:no memory!\n");
            result = -ENOMEM;

            goto _error_file;
        }
        rt_memset(dfs_lfs_fd,0,sizeof(dfs_lfs_fd_t));
        dfs_lfs_fd->lfs = &dfs_lfs->lfs;


        if ((file->flags & 3) == O_RDONLY)  flags |= LFS_O_RDONLY;
        if ((file->flags & 3) == O_WRONLY)  flags |= LFS_O_WRONLY;
        if ((file->flags & 3) == O_RDWR)    flags |= LFS_O_RDWR;
        if (file->flags & O_CREAT)          flags |= LFS_O_CREAT;
        if (file->flags & O_EXCL)           flags |= LFS_O_EXCL;
        if (file->flags & O_TRUNC)          flags |= LFS_O_TRUNC;
        if (file->flags & O_APPEND)         flags |= LFS_O_APPEND;

        result = lfs_file_open(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->path, flags);
        if (result != LFS_ERR_OK)
        {
            goto _error_file;
        }

        file->data = (void *)dfs_lfs_fd;
        return RT_EOK;

_error_file:
        if(dfs_lfs_fd != RT_NULL)
            rt_free(dfs_lfs_fd);

        return lfs_result_to_dfs(result);
    }
    return 0;
}

static int dfs_lfs_close(struct dfs_fd *file)
{
    int result;
    dfs_lfs_fd_t*   dfs_lfs_fd;
    RT_ASSERT(file != RT_NULL);
    RT_ASSERT(file->data != RT_NULL);
    dfs_lfs_fd  = (dfs_lfs_fd_t *)file->data;

    if (file->type == FT_DIRECTORY)
    {

        result = lfs_dir_close(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir);
    }
    else
    {
        result = lfs_file_close(dfs_lfs_fd->lfs,&dfs_lfs_fd->u.file);
    }
    rt_free(dfs_lfs_fd);
    return lfs_result_to_dfs(result);
}

static int dfs_lfs_ioctl(struct dfs_fd *file, int cmd, void *args)
{
    return -ENOSYS;
}

int dfs_lfs_read(struct dfs_fd *file, void *buf, size_t len)
{
    int result;
    lfs_ssize_t ssize;
    dfs_lfs_fd_t*   dfs_lfs_fd;
    RT_ASSERT(file != RT_NULL);
    RT_ASSERT(file->data != RT_NULL);
    dfs_lfs_fd = (dfs_lfs_fd_t*)file->data;

    if (file->type == FT_DIRECTORY)
    {
        return -EISDIR;
    }

    if(lfs_file_tell(dfs_lfs_fd->lfs,&dfs_lfs_fd->u.file) != file->pos)
    {
        lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->pos, LFS_SEEK_SET);
        if (soff < 0)
        {
            return lfs_result_to_dfs(soff);
        }
    }

    ssize = lfs_file_read(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file,buf,len);
    if(ssize < 0)
    {
        return lfs_result_to_dfs(ssize);
    }

    /* update position */
    file->pos  = dfs_lfs_fd->u.file.pos;

    return ssize;
}


int dfs_lfs_write(struct dfs_fd *file, const void *buf, size_t len)
{
    int result;
    lfs_ssize_t ssize;
    dfs_lfs_fd_t*   dfs_lfs_fd;
    RT_ASSERT(file != RT_NULL);
    RT_ASSERT(file->data != RT_NULL);

    if (file->type == FT_DIRECTORY)
    {
        return -EISDIR;
    }

    dfs_lfs_fd = (dfs_lfs_fd_t *)file->data;
    if(lfs_file_tell(dfs_lfs_fd->lfs,&dfs_lfs_fd->u.file) != file->pos)
    {
        lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->pos, LFS_SEEK_SET);
        if (soff < 0)
        {
            return lfs_result_to_dfs(soff);
        }
    }

    ssize = lfs_file_write(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, buf, len);
    if(ssize < 0)
    {
        return lfs_result_to_dfs(ssize);
    }

    /* update position and file size */
    file->pos  = dfs_lfs_fd->u.file.pos;
    file->size = dfs_lfs_fd->u.file.size;
    return ssize;
}

int dfs_lfs_flush(struct dfs_fd *file)
{
    int result;
    dfs_lfs_fd_t*   dfs_lfs_fd;
    RT_ASSERT(file != RT_NULL);
    RT_ASSERT(file->data != RT_NULL);

    dfs_lfs_fd = (dfs_lfs_fd_t *)file->data;

    result = lfs_file_sync(dfs_lfs_fd->lfs,&dfs_lfs_fd->u.file);

    return lfs_result_to_dfs(result);
}

int dfs_lfs_lseek(struct dfs_fd *file, rt_off_t offset)
{
    int result;
    dfs_lfs_fd_t*   dfs_lfs_fd;
    RT_ASSERT(file != RT_NULL);
    RT_ASSERT(file->data != RT_NULL);

    dfs_lfs_fd = (dfs_lfs_fd_t *)file->data;

    if (file->type == FT_REGULAR)
    {
        lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, offset, LFS_SEEK_SET);
        if (soff < 0)
        {
            return lfs_result_to_dfs(soff);
        }

        file->pos = dfs_lfs_fd->u.file.pos;
    }
    else if (file->type == FT_DIRECTORY)
    {
        lfs_soff_t soff = lfs_dir_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, offset);
        if (soff < 0)
        {
            return lfs_result_to_dfs(soff);
        }

        file->pos = dfs_lfs_fd->u.dir.pos;
    }

    return (file->pos);
}


int dfs_lfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
{
    dfs_lfs_fd_t*   dfs_lfs_fd;
    int result;
    int index;
    struct dirent *d;
    struct lfs_info info;

    RT_ASSERT(file->data != RT_NULL);
    dfs_lfs_fd = (dfs_lfs_fd_t *)(file->data);

    /* make integer count */
    count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
    if (count == 0)
        return -EINVAL;

    index = 0;
    while (1)
    {
        char *fn;

        d = dirp + index;

        result = lfs_dir_read(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, &info);
        if ((result != 1) || (info.name[0] == 0))
        {
            return result;
        }

        d->d_type = DT_UNKNOWN;
        switch (info.type)
        {
            case LFS_TYPE_DIR:
                d->d_type |= DT_DIR;
            break;
            case LFS_TYPE_REG:
                d->d_type |= DT_REG;
            break;
        }

        d->d_namlen = (rt_uint8_t)rt_strlen(info.name);
        d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
        rt_strncpy(d->d_name, info.name, rt_strlen(info.name) + 1);

        index ++;
        if (index * sizeof(struct dirent) >= count)
            break;
    }

    if (index == 0)
        return lfs_result_to_dfs(result);
    file->pos += index * sizeof(struct dirent);

    return index * sizeof(struct dirent);
}


static const struct dfs_file_ops _dfs_lfs_fops =
{
    dfs_lfs_open,
    dfs_lfs_close,
    dfs_lfs_ioctl,
    dfs_lfs_read,
    dfs_lfs_write,
    dfs_lfs_flush,
    dfs_lfs_lseek,
    dfs_lfs_getdents,
//    RT_NULL, /* poll interface */
};

static const struct dfs_filesystem_ops _dfs_lfs_ops =
{
    "lfs",
    DFS_FS_FLAG_DEFAULT,
    &_dfs_lfs_fops,

    dfs_lfs_mount,
    dfs_lfs_unmount,

    dfs_lfs_mkfs,
    dfs_lfs_statfs,
    dfs_lfs_unlink,
    dfs_lfs_stat,
    dfs_lfs_rename,
};

int dfs_lfs_init(void)
{
    /* register ram file system */
    dfs_register(&_dfs_lfs_ops);

    return 0;
}
INIT_COMPONENT_EXPORT(dfs_lfs_init);

